﻿using DotNetCommon;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace DBUtil
{
    /// <summary>
    /// DBAccess的配置,参照:
    /// <code>
    /// db = DBFactory.CreateDB("MySql", "...", DBSetting.NewInstance()
    ///     .SetSqlMonitor(arg =>
    ///     {
    ///         Console.WriteLine(arg);
    ///     })
    ///     .SetWriteMonitor(arg =>
    ///     {
    ///         Console.WriteLine($"执行了对表 [{arg.TableName}] 的写入.");
    ///     }));
    /// </code>
    /// </summary>
    public class DBSetting
    {
        private DBSetting() { }
        public static DBSetting NewInstance() => new();

        #region Id和流水号生成
        public IIdSNOGenerator Generator { get; private set; }

        public DBSetting SetIdSNOGenerator(IIdSNOGenerator generator)
        {
            Ensure.NotNull(generator, nameof(generator));
            this.Generator = generator;
            return this;
        }
        #endregion

        #region 分布式锁
        public ILocker Locker { get; private set; }

        public DBSetting SetLocker(ILocker locker)
        {
            Ensure.NotNull(locker, nameof(locker));
            this.Locker = locker;
            return this;
        }
        #endregion

        private readonly ConcurrentDictionary<string, object> ExtendSettings = [];

        /// <summary>
        /// 添加扩展配置,可以从 <seealso cref="DBAccess"/> 中查询到,示例:
        /// <code>
        /// //添加配置
        /// DBSetting.NewInstance().AddExtendSetting("mysetting.name","小明");
        /// //取出配置
        /// var name = db.GetExtendSetting&lt;string>("mysetting.name");
        /// </code>
        /// </summary>
        public DBSetting AddExtendSetting(string key, object value)
        {
            ExtendSettings.AddOrUpdate(key, _ => value, (_, _) => value);
            return this;
        }

        internal Func<MonitorArgument, Task> MonitorAction { get; set; }
        /// <summary>
        /// 是否有sql监听器
        /// </summary>
        public bool HasMonitor => MonitorAction != null;

        /// <summary>
        /// 设置监听器,可以监听最终的sql执行情况
        /// </summary>
        /// <remarks>注意: 监听不到 BulkCopy 的信息</remarks>
        public DBSetting SetSqlMonitor(Func<MonitorArgument, Task> action)
        {
            MonitorAction = action;
            return this;
        }

        internal Func<AfterWriteArgument, Task> AfterWriteMonitorAction { get; set; }
        /// <summary>
        /// 是否有数据写入监听器
        /// </summary>
        public bool HasAfterWriteMonitor => AfterWriteMonitorAction != null;
        /// <summary>
        /// 设置数据写入监听器
        /// </summary>
        public DBSetting SetWriteMonitor(Func<AfterWriteArgument, Task> action)
        {
            AfterWriteMonitorAction = action;
            return this;
        }

        internal T GetExtendSetting<T>(string key)
        {
            if (ExtendSettings.TryGetValue(key, out var value))
            {
                return (T)value;
            }
            return default;
        }
        internal object GetExtendSetting(string key)
        {
            if (ExtendSettings.TryGetValue(key, out var value))
            {
                return value;
            }
            return default;
        }

        #region GetDefaultDbType
        internal Func<Type, string> _getDefaultDbType = null;
        internal string GetDefaultDbtype(DBAccess db, Type type)
        {
            var def = _getDefaultDbType?.Invoke(type);
            if (def == null) def = db.GetDefaultDbType(type);
            return def;
        }
        public DBSetting SetGetDefaultDbtype(Func<Type, string> func)
        {
            _getDefaultDbType = func;
            return this;
        }
        #endregion
    }

    /// <summary>
    /// 写入完成后的监听参数
    /// </summary>
    public struct AfterWriteArgument
    {
        /// <summary>
        /// 写入类型
        /// </summary>
        public EnumWriteType WriteType { get; set; }
        /// <summary>
        /// 表名称
        /// </summary>
        public string TableName { get; set; }
        /// <summary>
        /// 表配置信息, 可能为空
        /// </summary>
        public EntityInfo EntityInfo { get; set; }

        public override readonly string ToString()
        {
            return $"{{\"TableChanged\":\"true\", \"TableName\":\"{TableName}\",\"WriteType\":\"{WriteType}\"}}";
        }
    }

    /// <summary>
    /// 数据写入类型
    /// </summary>
    public enum EnumWriteType
    {
        Insert,
        InsertFromSelect,
        Update,
        Delete,
        BulkCopy,
        SaveOne,
    }

    /// <summary>
    /// 监听器参数
    /// </summary>
    public struct MonitorArgument
    {
        public string Sql { get; set; }
        public Exception Exception{ get; set; }
        public TimeSpan TimeSpan { get; set; }

        public override readonly string ToString()
        {
            return $@"
------------------------ execute sql ------------------------------
{Sql}
================= 耗时: {TimeSpan.TotalMilliseconds} 毫秒 ===============
";
        }
    }
}
